package com.jyt.motor.service.impl;

import com.jyt.motor.constant.ComConstant;
import com.jyt.motor.dao.*;
import com.jyt.motor.model.MoArea;
import com.jyt.motor.model.MoDataReport;
import com.jyt.motor.model.MoMotors;
import com.jyt.motor.service.MoReportService;
import com.jyt.motor.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
@Slf4j
public class MoReportServiceImp implements MoReportService {
    @Autowired
    MoDataReportMapper moDataReportMapper;
    @Autowired
    MoAreaMapper moAreaMapper;
    @Autowired
    MoMotorsMapper moMotorsMapper;
    @Autowired
    MoAlertRecMapper moAlertRecMapper;
    @Autowired
    MoDataRecMapper moDataRecMapper;

    @Autowired
    AlarmLampServiceImpSerialPort alarmLampServiceImpSerialPort;


    @Override
    public LinkedHashMap getTimeTrend(CallParaMotorsChart callPara) {
        LinkedHashMap mmpTemp = new LinkedHashMap<String, Map<Integer, ChartView>>();
        //
        List<MotorView> motorViewList = moMotorsMapper.motorViewsSelect();
        Map<Integer, MotorView> motorsMap = new HashMap<>();
        for (MotorView mv : motorViewList) {
            motorsMap.put(mv.getMoId(), mv);
        }
        //
        List<Integer> listTemp = new ArrayList<>();
        if (StringUtils.isNotBlank(callPara.getMoIds())) {
            String[] x = callPara.getMoIds().split(",");
            //排除掉非数字的，和不正确的moId
            for (String id : x) {
                if (StringUtils.isNotBlank(id)) {
                    Integer moid = Integer.valueOf(id);
                    if (motorsMap.containsKey(moid)) {
                        listTemp.add(moid);
                    }
                }
            }
        }
        List<MoDataReport> list = moDataReportMapper.selectByCPChat(callPara.getTrendType(), listTemp,
                callPara.getStartTime(), callPara.getEndTime());
        //
        for (MoDataReport report : list) {
            Map<Integer, ChartView> childMap = (Map<Integer, ChartView>) mmpTemp.get(report.getTimeArea());
            if (childMap == null) {
                childMap = new HashMap<Integer, ChartView>();
                for (Integer moid : listTemp) {
                    MotorView mv = motorsMap.get(moid);
                    ChartView cv = new ChartView();
                    cv.setAreaId(mv.getAreaId());
                    cv.setAreaName(mv.getAreaName());
                    cv.setChartType(callPara.getTrendType());
                    String showName = callPara.getTrendType() == 1 ? "时" : (callPara.getTrendType() == 2 ? "日" : "月");
                    cv.setChartTypeShow(showName);
                    cv.setMoId(mv.getMoId());
                    cv.setMoName(mv.getMoName());
                    cv.setUpperLimitInner(mv.getUpperLimitInner());
                    cv.setLowerLimitInner(mv.getLowerLimitInner());
                    childMap.put(moid, cv);
                }
                mmpTemp.put(report.getTimeArea(), childMap);
            }
            //
            ChartView cv = childMap.get(report.getMoId());
            cv.setRecTime(report.getTimeArea());
            cv.setRockData(report.getData());
            cv.setMaintainRate(report.getMaintainRate());
            cv.setFailureRate(report.getFailureRate());
            cv.setDynamicRate(report.getDynamicRate());
            childMap.put(report.getMoId(), cv);
        }
        //
        LinkedHashMap mmp = new LinkedHashMap<String, ChartView[]>();
        for (Object entry : mmpTemp.entrySet()) {
            Map.Entry<String, Map<Integer, ChartView>> mentry = (Map.Entry<String, Map<Integer, ChartView>>) entry;
            Map<Integer, ChartView> innKP = mentry.getValue();
            mmp.put(mentry.getKey(), innKP.values().toArray());
        }
        //
        return mmp;
    }

    @Override
    public DashboardStatisticMod getStatisticInfo(Integer periods) {
        DashboardStatisticMod resultMod = new DashboardStatisticMod();
        Integer offlineNum = 0;
        Integer normalNum = 0;
        Integer exceptNum = 0;
        Integer maintainNum = 0;
        List<MoMotors> list = moMotorsMapper.selectMortorByPeriods(periods);
        for (int i = list.size() - 1; i >= 0; i--) {
            MoMotors motor = list.get(i);
            //移除未安装监测器的马达
            if (motor.getMonitorId() == null || motor.getMonitorId() == 0) {
                list.remove(motor);
                continue;
            }
            if (motor.getMoState() == 0) {
                offlineNum++;
            } else if (motor.getMoState() == 1) {
                //马达异常数
                normalNum++;
            } else if (motor.getMoState() == 2) {
                //马达异常数
                exceptNum++;
            } else if (motor.getMoState() == 3) {
                //马达正常数
                maintainNum++;
            }
        }
        resultMod.setTotalNum(list.size());
        resultMod.setOfflineNum(offlineNum);
        resultMod.setNormalNum(normalNum);
        resultMod.setExceptNum(exceptNum);
        resultMod.setMaintainNum(maintainNum);
        //
        if (list.size() != 0) {
            //计算正常率
            BigDecimal rate = new BigDecimal(normalNum * 100)
                    .divide(new BigDecimal(list.size()), 2, RoundingMode.HALF_UP);
            resultMod.setNormalRate(rate.toString() + "%");
        } else {
            resultMod.setNormalRate("0.00%");
        }
        return resultMod;
    }

    @Override
    public List<DashboardAlertInfo> getAlertInfo(Integer periods) {
        return moAlertRecMapper.moAlertInfoDashboard(periods);
    }

    @Override
    public List<DashboardAreaMotors> getAreaMotors(Integer periods) {
        //
        List<MoMotors> motorsList = moMotorsMapper.selectMortorByPeriods(periods);
        //
        Map<Integer, DashboardAreaMotors> areaMap = new HashMap<>();
        List<MoArea> listArea = moAreaMapper.selectAll();
        for (MoArea moarea : listArea) {
            DashboardAreaMotors am = new DashboardAreaMotors();
            am.setAreaId(moarea.getAreaId());
            am.setAreaName(moarea.getAreaName());
            am.setSortSn(moarea.getSortSn());
            am.setAreaPId(moarea.getAreaPId());
            am.setLevelNo(moarea.getLevelNo());
            am.setMotorInfos(new ArrayList<>());
            //
            areaMap.put(moarea.getAreaId(), am);
        }
        //
        for (MoMotors motor : motorsList) {
            DashboardAreaMotors am = areaMap.get(motor.getAreaId());
            if (am != null) {
                DashboardMotorInfo dashboardMotor = new DashboardMotorInfo();
                dashboardMotor.setAreaId(motor.getAreaId());
                dashboardMotor.setMoId(motor.getMoId());
                dashboardMotor.setMoName(motor.getMoName());
                dashboardMotor.setMoState(motor.getMoState());
                if (motor.getMoState() != null && motor.getMoState() == 3) {
                    dashboardMotor.setMoOpenState("-1");
                } else {
                    dashboardMotor.setMoOpenState("1");
                }
                dashboardMotor.setMoHealthState(motor.getMoLight());
                dashboardMotor.setMoAlertId(0);
                am.getMotorInfos().add(dashboardMotor);
            }
        }
        //
        return new ArrayList<>(areaMap.values());
    }

    @Override
    public Integer makeProcess(Integer periods, Integer moId, Integer openState) {
        Integer total = 0;
        List<Integer> listMoId = new ArrayList<>();
        //openState=1:开线, -1:关线保养
        Integer moState = openState == 1 ? 1 : 3;
        String color = openState == 1 ? "green" : "blue";
        if (moId != null && moId > 0) {
            MoMotors motor = new MoMotors();
            motor.setMoId(moId);
            motor.setMoState(moState);
            motor.setMoLight(color);
            total = moMotorsMapper.updateByPrimaryKeySelective(motor);
            listMoId.add(moId);
        } else if (periods != null && periods > 0) {
            List<MoMotors> motors = moMotorsMapper.selectMortorByPeriods(periods);
            for (MoMotors temp : motors) {
                MoMotors motor = new MoMotors();
                motor.setMoId(temp.getMoId());
                motor.setMoState(moState);
                motor.setMoLight(color);
                total += moMotorsMapper.updateByPrimaryKeySelective(motor);
                listMoId.add(temp.getMoId());
            }
        }
        if (openState == -1 && listMoId.size() > 0) {
            //保养时清除未处理异常
            moAlertRecMapper.updateRecoveryByMoIds(Calendar.getInstance().getTime(), "切换保养状态", listMoId);
        }
        return total;
    }

    @Override
    public Integer closeAlarmLamp() {
        try {
            alarmLampServiceImpSerialPort.closeAlarmLamp();
            moAlertRecMapper.updateDealing("手动关闭报警灯");
            return 1;
        } catch (Exception exc) {
            return 0;
        }
    }

    @Override
    public List<DashboardRecentInfo> getRecent5(Integer moId) {
        return moDataRecMapper.selectRecent(moId);
    }

    private Date getNowTimeWithHour(Calendar calNow) {
        if (calNow == null) {
            calNow = Calendar.getInstance();
        }
        calNow.roll(Calendar.MINUTE, -1 * calNow.get(Calendar.MINUTE));
        calNow.roll(Calendar.SECOND, -1 * calNow.get(Calendar.SECOND));
        calNow.roll(Calendar.MILLISECOND, -1 * calNow.get(Calendar.MILLISECOND));
        return calNow.getTime();
    }

    private Date getNowDate(Calendar calNow) {
        if (calNow == null) {
            calNow = Calendar.getInstance();
        }
        calNow.roll(Calendar.MINUTE, -1 * calNow.get(Calendar.MINUTE));
        calNow.roll(Calendar.SECOND, -1 * calNow.get(Calendar.SECOND));
        calNow.roll(Calendar.MILLISECOND, -1 * calNow.get(Calendar.MILLISECOND));
        calNow.roll(Calendar.HOUR_OF_DAY, -1 * calNow.get(Calendar.HOUR_OF_DAY));
        return calNow.getTime();
    }

    private Date getNowMonth(Calendar calNow) {
        if (calNow == null) {
            calNow = Calendar.getInstance();
        }
        calNow.roll(Calendar.MINUTE, -1 * calNow.get(Calendar.MINUTE));
        calNow.roll(Calendar.SECOND, -1 * calNow.get(Calendar.SECOND));
        calNow.roll(Calendar.MILLISECOND, -1 * calNow.get(Calendar.MILLISECOND));
        calNow.roll(Calendar.HOUR_OF_DAY, -1 * calNow.get(Calendar.HOUR_OF_DAY));
        calNow.roll(Calendar.DAY_OF_MONTH, -1 * calNow.get(Calendar.DAY_OF_MONTH));
        return calNow.getTime();
    }

    private Date getFromTimeWithHourFrom(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return getNowTimeWithHour(calendar);
    }

    SimpleDateFormat sdfMinute = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
    SimpleDateFormat sdfMonth = new SimpleDateFormat("yyyy-MM");

    @Override
    public void generateReportHourly() {
        log.info("Start generating hour Report......");
        try {
            List<MotorLatestRepIdView> list = moMotorsMapper.selectAllLatestRepId();
            Date fromTime = null, toTime = null;
            Calendar calendar = Calendar.getInstance();
            Date nowHour = getNowTimeWithHour(calendar);
            for (MotorLatestRepIdView mo : list) {
                if (mo.getLatestHourlyId() == null || mo.getLatestHourlyId() <= 0) {
                    Date temp = moDataRecMapper.getEarliestRecTime(mo.getMoId());
                    if (temp != null) {
                        fromTime = getFromTimeWithHourFrom(temp);
                    } else {
                        //没值时不计算
                        continue;
                    }
                } else {
                    MoDataReport rep = moDataReportMapper.selectByPrimaryKey(mo.getLatestHourlyId());
                    try {
                        fromTime = sdfMinute.parse(rep.getTimeArea());
                        fromTime = DateUtils.addHours(fromTime, 1);
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }
                while (fromTime.compareTo(nowHour) < 0) {
                    MoDataReport report = new MoDataReport();
                    report.setMoId(mo.getMoId());
                    report.setTime(Calendar.getInstance().getTime());
                    report.setTimeArea(sdfMinute.format(fromTime));
                    report.setType(ComConstant.HOURLY_REPORT);
                    Long keyid = moDataReportMapper.existModelByLogicKey(report);
                    toTime = DateUtils.addHours(fromTime, 1);
                    //
                    DataAvgVo avg = moDataRecMapper.getMoRockDataAvgVo(mo.getMoId(), fromTime, toTime);
                    fromTime = DateUtils.addHours(fromTime, 1);
                    if (avg==null|| avg.getAvgData() == null) {
                        //当前无记录，则跳过
                        continue;
                    }
                    report.setData(avg.getAvgData());
                    report.setLowerLimit(avg.getAvgLowerLimit());
                    report.setUpperLimit(avg.getAvgUpperLimit());
                    report.setMaintainRate(avg.getMaintainRate());
                    report.setFailureRate(avg.getFailureRate());
                    report.setDynamicRate(avg.getDynamicRate());
                    moDataReportMapper.insertSelective(report);
                    mo.setLatestHourlyId(report.getId());
                    moMotorsMapper.updateLatestRepIdById(mo);
                }
            }
        }catch (Exception e)
        {
            log.error(e.getMessage(),e);
        }
        log.info("End generating hour Report......");
    }

    @Override
    public void generateReportDaily() {
        log.info("Start generating daily Report......");
        try {
            List<MotorLatestRepIdView> list = moMotorsMapper.selectAllLatestRepId();
            Date startDay = null, endDay = null;
            Calendar calendar = Calendar.getInstance();
            Date today = getNowDate(calendar);
            for (MotorLatestRepIdView mo : list) {
                String fromDate = null, toDate = null;
                if (mo.getLatestDailyId() == null || mo.getLatestDailyId() <= 0) {
                    //如果日报从来没计算过，取最早的小时报ID
                    Long tkey = moDataReportMapper.getEarliestByMoId(1, mo.getMoId());
                    if (tkey != null) {
                        MoDataReport repTemp = moDataReportMapper.selectByPrimaryKey(tkey);
                        try {
                            startDay = sdfDate.parse(repTemp.getTimeArea().substring(0, 10));
                        } catch (ParseException e) {
                            e.printStackTrace();
                        }
                    } else {
                        //如果小时报还未计算，跳过，不计算日报
                        continue;
                    }
                } else {
                    //如果日报计算过，取上次计算过的日报ID
                    MoDataReport rep = moDataReportMapper.selectByPrimaryKey(mo.getLatestDailyId());
                    try {
                        startDay = sdfDate.parse(rep.getTimeArea());
                        startDay = DateUtils.addDays(startDay, 1);
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }
                while (startDay.compareTo(today) < 0) {
                    MoDataReport report = new MoDataReport();
                    report.setMoId(mo.getMoId());
                    report.setTime(Calendar.getInstance().getTime());
                    report.setTimeArea(sdfDate.format(startDay));
                    report.setType(ComConstant.DAILY_REPORT);
                    endDay = DateUtils.addDays(startDay, 1);
                    DataAvgVo avg = moDataReportMapper.getMoDataAvgVo(mo.getMoId(), 1, sdfDate.format(startDay), sdfDate.format(endDay));
                    startDay = DateUtils.addDays(startDay, 1);
                    if (avg==null||avg.getAvgData() == null) {
                        //如果当天内没有小时记录，则不计算日报
                        continue;
                    }
                    report.setData(avg.getAvgData());
                    report.setLowerLimit(avg.getAvgLowerLimit());
                    report.setUpperLimit(avg.getAvgUpperLimit());
                    report.setMaintainRate(avg.getMaintainRate());
                    report.setFailureRate(avg.getFailureRate());
                    report.setDynamicRate(avg.getDynamicRate());
                    moDataReportMapper.insertSelective(report);
                    mo.setLatestDailyId(report.getId());
                    moMotorsMapper.updateLatestRepIdById(mo);
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        log.info("End generating daily Report......");
    }

    @Override
    public void generateReportMonthly() {
        log.info("Start generating monthly Report......");
        try {
            List<MotorLatestRepIdView> list = moMotorsMapper.selectAllLatestRepId();
            Date startMonth = null, endMonth = null;
            Calendar calendar = Calendar.getInstance();
            Date today = getNowMonth(calendar);
            for (MotorLatestRepIdView mo : list) {
                //String fromDate = null, toDate = null;
                if (mo.getLatestMonthlyId() == null || mo.getLatestMonthlyId() <= 0) {
                    //如果月报从来没计算过，取最早的日报ID
                    Long tkey = moDataReportMapper.getEarliestByMoId(2, mo.getMoId());
                    if (tkey != null) {
                        MoDataReport repTemp = moDataReportMapper.selectByPrimaryKey(tkey);
                        try {
                            startMonth = sdfDate.parse(repTemp.getTimeArea().substring(0, 7));
                        } catch (ParseException e) {
                            e.printStackTrace();
                        }
                    } else {
                        //如果小时报还未计算，跳过，不计算日报
                        continue;
                    }
                } else {
                    //如果日报计算过，取上次计算过的日报ID
                    MoDataReport rep = moDataReportMapper.selectByPrimaryKey(mo.getLatestMonthlyId());
                    try {
                        startMonth = sdfDate.parse(rep.getTimeArea());
                        startMonth = DateUtils.addMonths(startMonth, 1);
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }
                while (startMonth.compareTo(today) < 0) {
                    MoDataReport report = new MoDataReport();
                    report.setMoId(mo.getMoId());
                    report.setTime(Calendar.getInstance().getTime());
                    report.setTimeArea(sdfMonth.format(startMonth));
                    report.setType(ComConstant.MONTHLY_REPORT);
                    endMonth = DateUtils.addMonths(startMonth, 1);
                    DataAvgVo avg = moDataReportMapper.getMoDataAvgVo(mo.getMoId(), 2, sdfMonth.format(startMonth), sdfMonth.format(endMonth));
                    startMonth = DateUtils.addMonths(startMonth, 1);
                    if (avg==null||avg.getAvgData() == null) {
                        continue;
                    }
                    report.setData(avg.getAvgData());
                    report.setLowerLimit(avg.getAvgLowerLimit());
                    report.setUpperLimit(avg.getAvgUpperLimit());
                    report.setMaintainRate(avg.getMaintainRate());
                    report.setFailureRate(avg.getFailureRate());
                    report.setDynamicRate(avg.getDynamicRate());
                    moDataReportMapper.insertSelective(report);
                    mo.setLatestDailyId(report.getId());
                    moMotorsMapper.updateLatestRepIdById(mo);
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        log.info("End generating monthly Report......");
    }

}